package io.hepu.robotize.storage;

import io.hepu.robotize.websocket.ProgressWebSocketHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

@Service
public class FileService implements IFileService {

    @Value("${spring.servlet.upload-dir}")
    private String uploadDir;

    @PostConstruct
    public void init() {
        File directory = new File(uploadDir);
        if (!directory.exists()) {
            boolean created = directory.mkdirs();
            if (!created) {
                throw new RuntimeException("Failed to create upload directory: " + uploadDir);
            }
        }
    }

    @Override
    public String upload(MultipartFile file, String sessionId) throws IOException {
        if (file.isEmpty()) {
            throw new RuntimeException("Please select a file to upload.");
        }

        String fileName = file.getOriginalFilename();
        File destFile = new File(uploadDir + fileName);

        try (FileOutputStream fos = new FileOutputStream(destFile); FileChannel fileChannel = fos.getChannel()) {

            ByteBuffer buffer = ByteBuffer.wrap(file.getBytes());
            int totalBytes = buffer.remaining();
            int bytesWritten = 0;

            while (buffer.hasRemaining()) {
                bytesWritten += fileChannel.write(buffer);
                int progress = (int) ((bytesWritten / (double) totalBytes) * 100);
                ProgressWebSocketHandler.sendProgress(sessionId, progress);
            }
        }
        return "File uploaded successfully: " + fileName;
    }

    @Override
    public void download(String fileName, String sessionId, ServerHttpResponse response) throws IOException {
        File file = new File(uploadDir + fileName);
        if (!file.exists()) {
            response.setStatusCode(HttpStatus.NOT_FOUND);
            return;
        }

        response.getHeaders().setContentType(MediaType.APPLICATION_OCTET_STREAM);
        response.getHeaders().setContentDispositionFormData("attachment", fileName);
        response.getHeaders().setContentLength(file.length());

        try (FileInputStream fis = new FileInputStream(file); FileChannel fileChannel = fis.getChannel()) {

            ByteBuffer buffer = ByteBuffer.allocate(1024);
            long bytesTransferred = 0;

            DataBufferFactory dataBufferFactory = response.bufferFactory();
            while (fileChannel.read(buffer) > 0) {
                buffer.flip();
                DataBuffer dataBuffer = dataBufferFactory.allocateBuffer(buffer.remaining());
                dataBuffer.write(buffer);
                response.writeWith(Mono.just(dataBuffer));
                bytesTransferred += buffer.limit();
                buffer.clear();
                int progress = (int) ((bytesTransferred / (double) file.length()) * 100);
                ProgressWebSocketHandler.sendProgress(sessionId, progress);
            }
        }
    }
}
